package com.example.worklab.animation.utils

import android.graphics.Point
import android.graphics.PointF
import androidx.annotation.IntRange

class BezierUtils {
    companion object {
        const val X_TYPE = 1L
        const val Y_TYPE = 2L

        /**
         * 构建贝塞尔曲线，具体点数由参数frame决定
         * @controlPointList 控制点的坐标
         * @param frame   帧数
         */
        @JvmStatic
        fun buildBezierPoint(
            controlPointList: List<PointF>,
            frame: Int
        ): List<PointF> {
            val pointList = mutableListOf<PointF>()

            val delta = 1f / frame
            //阶数
            val order = controlPointList.size - 1
            // 浮点数for循环
            var u = 0f
            while (u <= 1f) {
                val x = calculatePointCoordinate(X_TYPE, u, order, 0, controlPointList)
                val y = calculatePointCoordinate(Y_TYPE, u, order, 0, controlPointList)
                pointList.add(PointF(x, y))
                u += delta
            }

            return pointList
        }

        /**
         * 计算贝塞尔曲线上某点的坐标
         * @param type                  X_TYPE 表示x坐标，Y_TYPE表示y坐标
         * @param u                     0<=u<=1,当前动画执行比例
         * @param k                     阶数
         * @param p                     当前坐标
         * @param controlPointList      控制点坐标
         * @return
         */
        @JvmStatic
        fun calculatePointCoordinate(
            @IntRange(from = X_TYPE, to = Y_TYPE) type: Long,
            u: Float,
            k: Int,
            p: Int,
            controlPointList: List<PointF>
        ): Float {
            /**
             * 公式解说：（p表示坐标点，后面的数字只是区分）
             * 场景：有一条线p1到p2，p0在中间，求p0的坐标
             *      p1◉--------○----------------◉p2
             *            u    p0
             *
             * 公式：p0 = p1+u*(p2-p1) 整理得出 p0 = (1-u)*p1+u*p2
             */
            if (k == 1) {// 一阶贝塞尔，直接返回
                val p1: Float
                val p2: Float
                // 根据是 x轴 还是 y轴 进行赋值
                if (type == X_TYPE) {
                    p1 = controlPointList[p].x
                    p2 = controlPointList[p + 1].x
                } else {
                    p1 = controlPointList[p].y
                    p2 = controlPointList[p + 1].y
                }
                return (1 - u) * p1 + u * p2
            } else {
                /**
                 * 这里应用了递归的思想：
                 * 1阶贝塞尔曲线的端点 依赖于 2阶贝塞尔曲线
                 * 2阶贝塞尔曲线的端点 依赖于 3阶贝塞尔曲线
                 * ....
                 * n-1阶贝塞尔曲线的端点 依赖于 n阶贝塞尔曲线
                 *
                 * 1阶贝塞尔曲线 则为 真正的贝塞尔曲线存在的点
                 */
                return (1 - u) * calculatePointCoordinate(
                    type, u, k - 1, p, controlPointList
                ) + u * calculatePointCoordinate(type, u, k - 1, p + 1, controlPointList)
            }
        }
    }
}